(* Release 3.00 *)

(*    clib1 - common misc stuff *)

(*    Copyright (C) 1989 Jensen and Partners. All Rights Reserved*)
(*    Written by Simon Knight.*)

(*    Copyright (C) 1991 Psion PLC. All Rights Reserved*)
(*    Written by NSM.*)

include "corelib.inc"
include "epocdefs.inc"

module clib1

segment _BSS(BSS, 28H)

public __stream : org DataPtrSize

(****************************************************************************)
section
segment _TEXT(CODE,28H)
segment _DATA(DATA,28H)

select _TEXT

public __swap :
(*
void _swap(void *p1, void *p2, size_t width)
swaps data at p1 with that at p2.
*)

    push di
    push si
    mov  si, ax
    mov  di, bx
swapLoop:
    mov  al, [di]
    movsb
    mov  [si][-1], al
    loop swapLoop
    pop  si
    pop  di
    ret  0

(* __swap ENDP *)

(****************************************************************************)
section
segment _TEXT(CODE,28H)
segment _DATA(DATA,28H)

select _TEXT

public __rotl :
(*
int _rotl(int val, int shift)
returns val rotated left by shift bits
*)

    push cx
    mov  cl, bl
    rol  ax, cl
    pop  cx
    ret  0

(* __rotl ENDP  *)

(****************************************************************************)
section
segment _TEXT(CODE,28H)
segment _DATA(DATA,28H)

select _TEXT

public __rotr :
(*
int _rotr(int val, int shift)
returns val rotated right by shift bits
*)

    push cx
    mov  cl, bl
    ror  ax, cl
    pop  cx
    ret  0

(* __rotl ENDP  *)

(****************************************************************************)
section
segment _TEXT(CODE,28H)
segment _DATA(DATA,28H)

select _TEXT

public __lrotl :
(*
long  _lrotl(long val, int shift)
returns val rotated left by shift bits
*)

    push cx
    mov  dx, bx
    and  cx, 31
llLoop:
    shl  ax, 1
    rcl  dx, 1
    jnc  llCarryZero
    or   ax, 1
llCarryZero:
    loop llLoop
    pop  cx
    ret  0

(* __rotl ENDP  *)

(****************************************************************************)
section
segment _TEXT(CODE,28H)
segment _DATA(DATA,28H)

select _TEXT

public __lrotr :
(*
long  _lrotr(long val, int shift)
returns val rotated right by shift bits
*)

    push cx
    mov  dx, bx
    and  cx, 31
lrLoop:
    shr  dx, 1
    rcr  ax, 1
    jnc  lrCarryZero
    or   dx, 8000H
lrCarryZero:
    loop lrLoop
    pop  cx
    ret  0

(* __rotl ENDP  *)

(****************************************************************************)
section
segment _TEXT(CODE,28H)
segment _DATA(DATA,28H)

select _TEXT

public _segread :          (* copies segment registers into SEGREGS *)
(*
void segread(struct SREGS *segregs)
*)

ES = 0
CS = 2
SS = 4
DS = 6

    push bx
    mov  bx, ax
    mov  [bx][ES], es
    mov  [bx][CS], cs
    mov  [bx][DS], ds
    mov  [bx][SS], ss
    pop  bx
    ret  0

(* _segread ENDP *)

(****************************************************************************)
section
segment _TEXT(CODE,28H)
segment _DATA(DATA,28H)

select _TEXT

public __enable :          (* enable interrupts *)
public _enable :

    sti
    ret  0

(* __enable ENDP *)

public __disable :          (* disable interrupts *)
public _disable :

    cli
    ret  0

(* __disable ENDP *)

(****************************************************************************)
section
segment _TEXT(CODE,28H)

select _TEXT

public _outportb :
public _outp :

    push dx
    mov  dx, ax
    mov  ax, bx
    out  byte dx, al
    pop	 dx
    ret  0

(****************************************************************************)
section
segment _TEXT(CODE,28H)

select _TEXT

public _outportw :
public _outpw :

    push dx
    mov  dx, ax
    mov  ax, bx
    out  word dx, ax
    pop	 dx
    ret  0

(****************************************************************************)
section
segment _TEXT(CODE,28H)

select _TEXT

public _inportb :
public _inp :

    push dx
    mov  dx, ax
    in   byte al, dx
    sub	 ah, ah
    pop	 dx
    ret  0

(****************************************************************************)
section
segment _TEXT(CODE,28H)

select _TEXT

public _inportw :
public _inpw :

    push dx
    mov  dx, ax
    in   word ax, dx
    pop  dx
    ret  0

(****************************************************************************)
section
segment _TEXT(CODE,28H)
segment _DATA(DATA,28H)

select _TEXT

public _stackavail :
(*
size_t stackavail(void)
returns bytes left in stack.
*)

    mov  ax, sp
    ret  0

(****************************************************************************)
section
segment _TEXT(CODE,28H)

select _TEXT

extrn __getDateAndTime

public _gettime :          (* gets system time *)
(*
void gettime(struct time *timeptr)
*)
hour    = 0
min     = 1
sec     = 2
hund    = 3
DataOsTimeInTicks = 420H
DataOsLcdType = 43BH

    push ax
    push bx
    push cx
    push dx
    push di
    push si
    mov  cx, ax
    call __getDateAndTime
    mov  si, cx
    mov	 ax, [di][DateHour]
    mov	 [si][hour], ax
    mov	 al, [di][DateSecond]
    mov	 [si][sec], al
    int	 GenDataSegment
    mov	 ax, es:[DataOsTimeInTicks]
    mov	 bl, es:[DataOsLcdType]
    cmp	 bl, Lcd640X200Small
    jbe	 doSiboClock
    cmp	 bl, Lcd160X80
    je	 doSiboClock
    cmp	 bl, Lcd240X80
    jne	 doPcClock
doSiboClock:
    test ax, ax
    jns	 stillPositive
    add	 al, 32
stillPositive:
    mov	 ah, al
    mov	 al, 32
    sub	 al, ah
    mov	 ah, al
    add	 al, ah
    add	 al, ah
    jmp	 setHundreds
doPcClock:
    sub	 dx, dx
    mov	 bx, 655
    div  bx
setHundreds:
    mov	 [si][hund], al
    pushf
    cli
    push ss
    pop	 es
    popf
    add	 sp, (DateEnt + DyScEnt)
    pop	 si
    pop  di
    pop	 dx
    pop  cx
    pop	 bx
    pop  ax
    ret  0

(****************************************************************************)
section
segment _TEXT(CODE,28H)

select _TEXT

extrn __getDateAndTime
extrn __setDateAndTime

public _settime :          (* sets system time *)
(*
void settime(struct time *timeptr)
*)

hour    = 0
min     = 1
sec     = 2
hund    = 3

    push ax
    push cx
    push di
    push si
    mov  cx, ax
    call __getDateAndTime
    mov  si, cx
    mov	 ax, [si][hour]
    mov	 [di][DateHour], ax
    mov	 al, [si][sec]
    mov	 [di][DateSecond], al
    call __setDateAndTime
    add	 sp, (DateEnt + DyScEnt)
    pop	 si
    pop  di
    pop  cx
    pop  ax
    ret  0

(*************************************************************************)
section
segment _TEXT(CODE,28H)

select _TEXT

extrn __getDateAndTime

public _getdate :          (* gets system date *)
(*
void getdate(struct date *dateptr)
*)

year    = 0
day     = 2
mon     = 3

    push ax
    push cx
    push di
    push si
    mov  cx, ax
    call __getDateAndTime
    mov  si, cx
    mov	 ax, [di][DateMonth]
    xchg ah, al
    add	 ax, 101H
    mov	 [si][day], ax
    mov	 al, [di][DateYear]
    sub	 ah, ah
    add	 ax, 1900
    mov	 [si][year], ax
    add	 sp, (DateEnt + DyScEnt)
    pop	 si
    pop  di
    pop  cx
    pop  ax
    ret  0

(****************************************************************************)
section
segment _TEXT(CODE,28H)

select _TEXT

extrn __getDateAndTime
extrn __setDateAndTime

public _setdate :          (* sets system date *)
(*
void setdate(struct date *dateptr)
*)

dateptr = frame
year    = 0
day     = 2
mon     = 3

    push ax
    push cx
    push di
    push si
    mov  cx, ax
    call __getDateAndTime
    mov  si, cx
    mov	 ax, [si][day]
    xchg ah, al
    sub	ax, 101H
    mov	 [di][DateMonth], ax
    mov	 ax, [si][year]
    sub	 ax, 1900
    mov	 [di][DateYear], al
    call __setDateAndTime
    add	 sp, (DateEnt + DyScEnt)
    pop	 si
    pop  di
    pop  cx
    pop  ax
    ret  0

(****************************************************************************)
section
segment _TEXT(CODE,28H)
segment _DATA(DATA,28H)

extrn __vp_flush
extrn __vp_ret
extrn __stream

select _TEXT

extrn __fputn
(*
void _str_out(char far *s, int flag, int wid, int prec)
*)

_NO_POINT = 10H
_L_JUST   = 1

file   = -2
s      = -4
flag   = -6
wid    = -8
prec   = -10
tmode  = -12                           (* 0 = file is text mode *)
locals = 14

public __str_out :                     (* internal function *)
    push bp
    mov  bp, sp
    sub  sp, locals
    push di
    push si
    mov  [bp][s], ax
    mov  [bp][flag], bx
    mov  [bp][wid],  cx
    mov  [bp][prec], dx
    mov  bx, cx                          (* bx = wid *)
    or   dx, dx
    jnz  FindLen
    test cx, _NO_POINT                   (* is No Precision bit set? *)
    jnz  FindLen
    mov  dx, 7FFFH
    mov  [bp][prec], dx                  (* [bp][prec] is now OK *)
FindLen:
    mov  di, [bp][s]                     (* di = s, find end of string *)
    mov  cx, -1
    sub  ax, ax
    cld
    repne;scasb
    not  cx
    dec  cx
    cmp  cx, dx
    jb   LenShorter
    mov  cx, dx
LenShorter:
    sub  bx, cx                          (* trash bx (wid) *)
    mov  cx, bx                          (* cx = pad length *)
(* stat: ax = 0 | bx = trash | cx = pad len | ~dx = prec | ~es:di = s *)
    mov  bx, [__stream]                  (* ds:bx = FILE [near DOS] *)
    mov  [bp][file], bx                  (* save FILE in file for __fputn *)
    mov  di, [bx][_flag]                 (* di = FILE flags *)
    and  di, _F_BIN                      (* is file text mode? *)
    mov  [bp][tmode], di
    mov  di, [bx][_ptr]                  (* es:di = FILE buffer *)
    sub  dx, dx                          (* dx is the output count *)
    mov  bx, [bx][_cnt]                  (* bx is _cnt *)
(* stat: ax = trash | bx = _cnt | cx = pad len | dx = out count | es:di = dest *)
    cmp  cx, 0
    jle  LeftPadDone
    test word [bp][flag], _L_JUST
    jnz  LeftPadDone
    mov  al, 20H
LeftPadLoop:
    dec  bx
    cmp  bx, 0                           (* have we run out of buffer space? *)
    jl   LeftClearBuffer
    stosb                                (* insert pad character *)
    inc  dx                              (* inc output counter *)
    loop LeftPadLoop
    jmp  LeftPadDone
LeftClearBuffer:
    call __fputn                         (* Clear the buffer *)
    mov  al, 20H
    jmp  LeftPadLoop
LeftPadDone:
    push cx                              (* save pad length *)
    mov  cx, [bp][prec]                  (* cx = precision *)
    jcxz StrOutDone
    mov  si, [bp][s]                     (* ds:si = s *)
    mov  ah, 0AH
StrOutLoop:
    lodsb
    cmp  ah, al                          (* is it a LineFeed? *)
    jz   TranslateLF
    or   al, al                          (* is it a 0C? *)
    jz   StrOutDone
JumpRet:
    dec  bx
    cmp  bx, 0                           (* buffer space check *)
    jl   StrOutClearBuffer
    stosb
    inc  dx                              (* inc output counter *)
    loop StrOutLoop
    jmp  StrOutDone
StrOutClearBuffer:
    push ax
    call __fputn
    pop  ax
    jmp  JumpRet
TranslateLF:
    cmp  byte [bp][tmode], 0             (* Binary Mode?, Don't translate *)
    jnz  JumpRet
    mov  al, 0DH
    dec  bx
    cmp  bx, 0
    jl   TranslateClearBuffer
    stosb
    mov  al, ah
    jmp  JumpRet
TranslateClearBuffer:
    call __fputn
    mov  ah, 0AH
    jmp  TranslateLF
StrOutDone:
    pop  cx
    cmp  cx, 0
    jle  RightPadDone
    test word [bp][flag], _L_JUST
    je   RightPadDone
    mov  al, 20H
RightPadLoop:
    dec  bx
    cmp  bx, 0
    jl   RightClearBuffer
    stosb
    inc  dx
    loop RightPadLoop
    jmp  RightPadDone
RightClearBuffer:
    call __fputn
    mov  al, 20H
    jmp  RightPadLoop
RightPadDone:
(* stat: ax = trash | bx = _cnt | cx = trash | dx = out count | es:di = end of dest *)
    add  [__vp_ret], dx
    mov  si, [__stream]                  (* ds:si = FILE *)
    mov  [si][_cnt], bx
    mov  [si][_ptr], di
    pop  si
    pop  di
    mov  sp, bp
    pop  bp
    ret  0

(****************************************************************************)
section
segment _TEXT(CODE,28H)
segment _DATA(DATA,28H)

extrn __vp_flush

select _TEXT

file   = -2

public __fputn :
    mov  ax, bx
    mov  bx, [bp][file]
    mov  [bx][_cnt], ax
    mov  [bx][_ptr], di
    push cx
    push dx
    push bx
    mov  ax, bx
    call [__vp_flush]
    pop  bx
    pop  dx
    pop  cx
    mov  di, [bx][_ptr]
    mov  bx, [bx][_cnt]
    ret  0

(****************************************************************************)
section
segment _TEXT(CODE,28H)
segment _DATA(DATA, 28H)

extrn __vp_flush
extrn __fputn

select _DATA

extrn __stream
extrn __vp_ret

select _TEXT

public __justify :         (* internal function *)
(*
void _justify(char *s, int flag, int wid)
*)

nopoint  =   10H
left     =    1H
zero     =   80H
VBUFSIZE =   256

temp     = -2
padchar  = -6
s        = -10
flag     = -12
wid      = -14
locals   =  14

    push bp
    mov  bp, sp
    sub  sp, locals
    push di
    push si
    mov  [bp][s], ax
    mov  [bp][flag], bx
    mov  [bp][wid], cx

    test word [bp][flag], ZFLAG
    jz   useSpace
    mov  dx, '0'
    jmp  gotPad
useSpace:
    mov  dx, 20H
gotPad:
    mov  [bp][padchar], dx
    mov  di, [bp][s]
    mov  cx, -1
    sub  ax, ax
repne ; scasb
    not  cx
    dec  cx
    mov  bx, [bp][wid]
    sub  bx, cx
    mov  cx, bx                  (* cx is pad length *)
    sub  dx, dx                  (* dx now output count *)
    mov  bx, [__stream]          (* ds:bx is FILE *)
    mov  [bp][temp], bx
    mov  di, [bx][_ptr]          (* es:di is destination *)
    mov  bx, [bx][_cnt]          (* bx is now _cnt, ds still FILE seg *)
    mov  si, [bp][s]
    cmp  cx, 0
    jle  pad1Done
    test word [bp][flag], left
    jnz  pad1Done
    add  dx, cx
    mov  al, [bp][padchar]
    cmp  al, '0'
    jnz  pad1Loop                (* handle laeding zeros in FP number *)
    cmp  byte [si], '-'
    je   pad0
    cmp  byte [si], '+'
    jnz  pad1Loop
pad0:
    dec  bx
    cmp  bx, 0
    jl   call0
    movsb
    inc  dx
pad1Loop:
    dec  bx
    cmp  bx, 0
    jl   call1
    stosb
    loop pad1Loop
    jmp  pad1Done
call0:
    call __fputn
    mov  al, [bp][padchar]
    jmp  pad0
call1:
    call __fputn
    mov  al, [bp][padchar]
    jmp  pad1Loop
pad1Done:
outLoop:
    lodsb
    or  al, al
    je  outDone
outRet:
    dec  bx
    cmp  bx, 0
    jl   call2
    stosb
    inc  dx
    jmp  outLoop
call2:
    push ax
    call __fputn
    pop  ax
    jmp  outRet
outDone:
    cmp  cx, 0
    jle  pad2Done
    test word [bp][flag], left
    je   pad2Done
    add  dx, cx
    mov  al, [bp][padchar]
pad2Loop:
    dec  bx
    cmp  bx, 0
    jl   call3
    stosb
    loop pad2Loop
    jmp  pad2Done
call3:
    call __fputn
    mov  al, [bp][padchar]
    jmp  pad2Loop
pad2Done:
    mov  si, [bp][temp]
    mov  [si][_cnt], bx
    mov  [si][_ptr], di
    add  [__vp_ret], dx
    pop  si
    pop  di
    mov  sp, bp
    pop  bp
    ret  0

(****************************************************************************)
section
segment _TEXT(CODE,28H)
segment _DATA(DATA,28H)

extrn __vp_flush

select _DATA

extrn __stream
extrn __vp_ret

select _TEXT

public __vputc :          (* internal function *)
(*
void _vputc(int ch)
*)

char  = -2
locals = 2

    push bp
    mov  bp, sp
    sub  sp, locals
    mov  [bp][char], ax
    inc  word [__vp_ret]           (* increment char count *)
    cmp  al, 0AH
    jne  vpRet
    mov  bx, [__stream]
    test word [bx][_flag], _F_BIN
    jnz  vpCont
    mov  ax, 0DH
    call __vputc
    mov  ax, 0AH
vpRet:
    mov  bx, [__stream]
vpCont:
    mov  ax, [bx][_cnt]         (* decrement stream count *)
    dec  ax
    js   vpCall
    mov  [bx][_cnt], ax
    mov  bx, [bx][_ptr]
    mov  al, [bp][char]
    mov  [bx], al               (* put character in buffer *)
    mov  bx, [__stream]
    inc  word [bx][_ptr]        (* increment pointer *)
    cmp  al, CTLZ
    jne  vpDone
    test word [bx][_flag], _F_BIN
    jz   vpDone
    or   word [bx][_flag], _F_CTZ
vpDone:
    mov  sp, bp
    pop  bp
    ret  0

vpCall:
    mov  ax, [__stream]
    call [__vp_flush]
    jmp  vpRet

(****************************************************************************)
section
segment _TEXT(CODE,28H)
segment _DATA(DATA,28H)

extrn __vs_fill
extrn _longjmp

select _DATA

extrn __stream
extrn __vs_count
extrn __EOFhandler

select _TEXT

public __vgetc :                   (* internal function *)
(*
int _vgetc()
*)

    push bp
    push bx
    mov  bp, sp
    inc  word [__vs_count]         (* increment char count *)
vsRet:
    mov  bx, [__stream]
    mov  ax, [bx][_cnt]         (* decrement stream count *)
    dec  ax
    js   vsCall
    mov  [bx][_cnt], ax
    mov  bx, [bx][_ptr]
    mov  al, [bx]               (* get character from buffer *)
    sub  ah, ah
    mov  bx, [__stream]
    inc  word [bx][_ptr]        (* increment pointer *)
    test word [bx][_flag], _F_BIN
    jnz  vsDone
    cmp  al, CTLZ
    jne  vsTrans
    mov  ax, -1
    jmp  vsError
vsTrans:
    cmp  al, 0DH
    jne  vsDone
    call __vgetc
vsDone:
vsError:
    pop  bx
    pop  bp
    ret  0

vsCall:
    mov  ax, [__stream]
    call [__vs_fill]
    cmp  ax, 0
    jg   vsRet
    jmp  vsError

(****************************************************************************)
section
segment _TEXT(CODE,28H)
segment _DATA(DATA,28H)

select _DATA

extrn __stream
extrn __vs_count

select _TEXT
public __vungetc :                 (* internal function *)
(*
int _vungetc(char)
*)

    cmp  ax, -1
    je   vunError
    dec  word [__vs_count]         (* decrement char count *)
    push bx
    mov  bx, [__stream]
    inc  word [bx][_cnt]        (* increment stream count *)
    dec  word [bx][_ptr]        (* decrement pointer *)
    pop  bx
vunError:
    ret  0

(*****************************************************************************)
section
segment _TEXT(CODE,28H)
segment _DATA(DATA,28H)

extrn __upperHex

select _TEXT

public _itoa :
(*
char  *itoa  ( value, strP, radix )
int   value
char *strP
int   radix

Convert a short integer value to ASCIIZ string at ( *strP ), using
a radix from 2..36.  If the radix is 10 and value is negative
then prefix the output by '-'.

The function return value equals strP.
*)

ita_value    =    -2
ita_strP     =    -6
ita_radix    =    -8
ita_buf      =    -26
locals  = 26

     push bp
     mov  bp, sp
     sub  sp, locals
     push dx
     push di
     push si
     mov  [bp][ita_value], ax
     mov  [bp][ita_strP], bx
     mov  [bp][ita_radix], cx
     mov  di, [bp][ita_strP]

(* If the request is invalid, generate an empty result*)

    mov  bx, [bp][ita_radix]
    cmp  bx, 36
    ja   ita_end
    cmp  bl, 2
    jb   ita_end

    mov  ax, [bp][ita_value]

(* If the radix is decimal, then if the value is negative*)
(*    put a sign on the result.*)

    cmp    bl, 10
    jne    ita_signSet
    or     ax, ax
    jnl    ita_signSet

    mov    byte [di][0], '-'
    inc    di
    neg    ax

ita_signSet:
    lea    si, [bp][ita_buf]
    mov    cx, si            (* CX remembers start of string*)

(* Now loop, taking each digit as modulo radix, and reducing the value*)
(*    by dividing by radix, until the value is zeroed.  Note that*)
(*    at least one loop occurs even if the value begins as 0,*)
(*    since we want "0" to be generated rather than "".*)

ita_shortLoop:
    sub    dx, dx
    div    bx
    mov    [si], dl
    inc    si
    or     ax, ax
    jnz    ita_shortLoop

(* The value has now been reduced to zero and the digits are in*)
(* the buffer.*)

    neg    cx
    add    cx, si            (* CX = length of the numeral*)

(* The digits in the buffer must now be copied in reverse order into*)
(* the target string, translating to ASCII as they are moved.*)

ita_copy:
    cld

ita_copyLoop:
    dec    si
    mov    al, [si]
    sub    al, 10
    jae    ita_alphaDigit
    add    al, '0' + 10
    jmp    ita_storeDigit

ita_alphaDigit:
    add    al, [__upperHex]

ita_storeDigit:
    stosb
    loop    ita_copyLoop

(* terminate the output string with a zero.*)

ita_end:
    mov    al, 0
    stosb

(* return a pointer to the string.*)

    mov  ax, [bp][ita_strP][0]
    pop  si
    pop  di
    pop  dx
    add  sp, locals
    pop  bp
    ret  0

(***************************************************************************)
section
segment _TEXT(CODE,28H)
segment _DATA(DATA,28H)

extrn __upperHex

select _TEXT
(*   ltoa - converts signed long integer to ASCIIZ string
     ultoa - converts unsigned long integer to ASCIIZ string
*)

public _ultoa :
(*
char  *ultoa  ( value, strP, radix )

long  value;
char *strP;
int   radix;

Convert an unsigned long integer value to ASCIIZ string at ( *strP),
using a radix from 2..36.  If the radix is 10 and value is negative
then prefix the output by '-'.

The parameters are identical to _ltoa except that the value is not
signed.  The function is implemented by jumping to shared code.

The function return value equals strP.
*)

lta_value  = -4
lta_strP   = -8
lta_radix  = -10
lta_buf    = -44
locals     =  44

    push bp
    mov  bp, sp
    sub  sp, locals
    push dx
    push di
    push si
    sub  si, si			(* flag indicates "not signed" *)
    jmp  lta_shared

(*  The major work is done by ltoa. *)

public _ltoa :
(*
char  *ltoa  ( value, strP, radix )

long  value;
char *strP;
int   radix;

Convert an signed long integer value to ASCIIZ string at ( *strP),
using a radix from 2..36.

The function return value equals strP.
*)


    push bp
    mov  bp, sp
    sub  sp, locals
    push dx
    push di
    push si
    mov  si, 1       (* flag indicates "may be signed" *)

(* ltoa jumps into here. *)

lta_shared:

    mov  [bp][lta_value], ax
    mov  [bp][lta_value][2], bx
    mov  [bp][lta_strP], cx
    mov  [bp][lta_radix], dx
    mov  di, [bp][lta_strP]

(* If the request is invalid, generate an empty result *)

    mov  bx, [bp][lta_radix]
    cmp  bx, 36
    ja   lta_end
    cmp  bl, 2
    jb   lta_end

    mov  ax, [bp][lta_value]
    mov  cx, [bp][lta_value][2]
    cmp  cx, 0
    jnl  lta_notSigned		(* Is the value signed or unsigned ? *)

    cmp  bl, 10	                (* only decimal numerals are signed *)
    jne  lta_notSigned
    or   si, si
    je   lta_notSigned

    mov  byte [di], '-'
    inc	 di
    not	 cx
    neg	 ax
    cmc		                 (*  negate CX:AX  *)
    adc  cx, 0

(* Now loop, taking each digit as modulo radix, and reducing the value
	by dividing by radix, until the value is zeroed.  Note that
	at least one loop occurs even if the value begins as 0,
	since we want "0" to be generated rather than "".
*)

lta_notSigned:                    (*  BX = radix,  CX:AX = value *)
    lea  si, [bp][lta_buf]
    jcxz lta_shortLoop

lta_longLoop:
    xchg cx, ax
    sub  dx, dx
    div  bx
    xchg ax, cx
    div  bx
    mov  [si], dl
    inc  si
    jcxz lta_shortTest	           (* does the value fit in 16 bits ? *)
    jmp  lta_longLoop

lta_shortLoop:
    sub  dx, dx
    div  bx
    mov  [si], dl
    inc  si
lta_shortTest:
    or   ax, ax
    jnz  lta_shortLoop

(* The value has now been reduced to zero and the digits are in
  the buffer.
*)
    lea  cx, [bp][lta_buf]
    neg  cx
    add  cx, si	             (* CX = length of numeral *)

(* The digits in the buffer must now be copied in reverse order into
   the target string, translating to ASCII as they are moved.
*)

lta_copy:
    cld

lta_copyLoop:
    dec  si
    mov  al, [si]
    sub	 al, 10
    jae	 lta_alphaDigit
    add  al, '0' + 10
    jmp	 lta_storeDigit

lta_alphaDigit:
    add   al, [__upperHex]

lta_storeDigit:
    stosb
    loop lta_copyLoop

(*  terminate the output string with a zero. *)

lta_end:
    mov  al, 0
    stosb

(* return a pointer to the string *)

    mov	 ax, [bp][lta_strP]
    pop  si
    pop  di
    pop  dx
    add  sp, locals
    pop  bp
    ret  0

(****************************************************************************)
section
segment _TEXT(CODE,28H)
segment _DATA(DATA,28H)
segment _INIT(DATA,28H)

extrn __clock_time           (* initialisation routine for clock function *)
extrn __InitLoop

select  _TEXT
do_initclock : (* defined later on ! *)

select _INIT
initclock : dw MAGIC
    	    db PR4
            dw do_initclock

select _DATA
public __proc_time :  dw  initclock, 0

select  _TEXT
    call __clock_time
    mov  [__proc_time], ax
    mov  [__proc_time][2], dx
    jmp  __InitLoop

(******************************************************************************)
section
segment _TEXT(CODE,28H)

public _memwmove :
(*
void *memwmove(void *dest, void *source, unsigned num)

Moves num words, selecting direction according to overlap.
Returns destination address.
*)

s_high =  -2
s_low  =  -4
num     = -6
locals =   6

    push bp
    mov  bp, sp
    sub  sp, locals
    push dx
    push di
    push si
    mov  si, bx
    mov  di, ax
    mov  [bp][num], cx
    push ax
    jcxz moveDone
    cmp  di, si
    jb   moveDown
    je   moveDone
moveUp:                      (* destination is higher *)
    std
    dec  cx
    shl  cx, 1
    add  si, cx
    add  di, cx
    mov  cx, [bp][num]
moveDown:                    (* destination is lower *)
rep  ;  movsw
    cld
moveDone:
    pop  ax                   (* return destination address. *)
    pop  si
    pop  di
    pop  dx
    mov  sp, bp
    pop  bp
    ret  0

(****************************************************************************)
section
segment _TEXT(CODE,28H)

public _memmove :
(*
void *memmove(void *dest, void *source, unsigned num)
Selects correct move direction and moves num bytes.
Returns destination address.
*)

s_high = -2
s_low  = -4
num    = -6
locals =  6

    push bp
    mov  bp, sp
    sub  sp, locals
    push dx
    push di
    push si
    mov  si, bx
    mov  di, ax
    push ax
    jcxz moveDone
    cmp  di, si
    jb   moveDown
    je   moveDone
moveUp:                        (* destination is higher *)
    std
    add  si, cx
    dec  si
    add  di, cx
    dec  di
moveDown:                      (* destination is lower *)
rep ;  movsb
    cld
moveDone:
    pop  ax                    (* return destination address *)
    pop  si
    pop  di
    pop  dx
    mov  sp, bp
    pop  bp
    ret  0

(****************************************************************************)
section
segment _TEXT(CODE,28H)

public _movmem :
(*
void *movmem(void *source, void *dest, unsigned num)
Selects correct move direction and moves num bytes.
Returns nothing.
*)

s_high = -2
s_low  = -4
num    = -6
locals =  6

    push bp
    mov  bp, sp
    sub  sp, locals
    push dx
    push di
    push si
    mov  si, ax
    mov  di, bx
    jcxz moveDone
    cmp  di, si
    jb   moveDown
    je   moveDone
moveUp:                      (* destination is higher *)
    std
    add  si, cx
    dec  si
    add  di, cx
    dec  di
moveDown:                    (* destination is lower *)
rep ;  movsb
    cld
moveDone:
    pop  si
    pop  di
    pop  dx
    mov  sp, bp
    pop  bp
    ret  0

(******************************************************************************)
section
segment _TEXT(CODE,28H)

public _swab :
(*
void swab(void *source, void *dest, unsigned num)
Moves num bytes, selecting direction according to overlap. Swaps byte order.
Returns nothing.
*)

    push dx
    push di
    push si
    mov  si, ax
    mov  di, bx
    shr  cx, 1
    jcxz moveDone
    cmp  di, si
    jb   moveDown
    je   moveDone
moveUp:                      (* destination is higher *)
    std
    push cx
    dec  cx
    shl  cx, 1
    add  si, cx
    add  di, cx
    pop	 cx
moveDown:                    (* destination is lower *)
swabLoop:
    lodsw
    xchg al, ah
    stosw
    loop swabLoop
    cld
moveDone:
    pop  si
    pop  di
    pop  dx
    ret  0

end

